package com.umpay.privi.dao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.springframework.orm.ibatis.SqlMapClientCallback;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapExecutor;
import com.ibatis.sqlmap.engine.execution.SqlExecutor;
import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
import com.umpay.common.persist.AbstractDao;
import com.umpay.common.persist.PageBean;
import com.umpay.common.persist.ReflectUtil;
import com.umpay.common.persist.ibatis.DataAccessException;
import com.umpay.common.persist.ibatis.exception.IntegrityViolationException;
import com.umpay.common.persist.ibatis.exception.SQLErrorCodeSQLExceptionTranslator;
import com.umpay.common.persist.ibatis.ext.LimitSqlExecutor;

/**
 * 负责为单个Entity 提供CRUD操作的IBatis DAO基类.<br/> 子类只要在类定义时指定所管理Entity的Class,
 * 即拥有对单个Entity对象的CRUD操作.
 * 
 * <pre>
 * public class UserDaoImpl extends EntityDaoImpl&lt;User&gt; {
 * }
 * </pre>
 * 
 * @author Jinlu
 * @version 2008.08.13
 * @see BaseDao, EntityDao
 */
@SuppressWarnings("unchecked")
public class EntityDaoImpl<T> extends SqlMapClientDaoSupport implements EntityDao<T> {

	protected static final String POSTFIX_FIND = ".Find";

	protected static final String POSTFIX_SELECT_PRIAMARYKEY = ".Get";

	protected static final String POSTFIX_SELECT_PRIAMARYKEYMAP = ".GetMap";

	protected static final String POSTFIX_INSERT = ".Insert";

	protected static final String POSTFIX_UPDATE = ".Update";
	
	private SqlExecutor sqlExecutor; 
	public SqlExecutor getSqlExecutor() { 
        return sqlExecutor; 
    } 

    public void setSqlExecutor(SqlExecutor sqlExecutor) { 
        this.sqlExecutor = sqlExecutor; 
    } 

    public void setEnableLimit(boolean enableLimit) { 
        if (sqlExecutor instanceof LimitSqlExecutor) { 
            ((LimitSqlExecutor) sqlExecutor).setEnableLimit(enableLimit); 
        } 
    } 
    public void initialize() throws Exception { 
        if (sqlExecutor != null) { 
        	SqlMapClient sqlMapClient = getSqlMapClientTemplate().getSqlMapClient(); 
            if (sqlMapClient instanceof ExtendedSqlMapClient) {
                ReflectUtil.setFieldValue(((ExtendedSqlMapClient) sqlMapClient).getDelegate(),
                         "sqlExecutor", SqlExecutor.class, sqlExecutor); 
            } 
        }
    }
        

	/**
	 * DAO所管理的Entity类型.
	 */
	protected Class<T> entityClass;

	public EntityDaoImpl() {
		entityClass = getSuperClassGenricType(getClass(), 0);
		//log.debug("Entity类型=" + entityClass.getName());
	}

	/*
	 * 根据条件查询对象列表（无分页）
	 * 
	 */
	public List<T> findBy(T t) throws DataAccessException {
		try {
			return getSqlMapClientTemplate().getSqlMapClient().queryForList(entityClass.getSimpleName() + POSTFIX_FIND, t);
		} catch (SQLException e) {
			throw new SQLErrorCodeSQLExceptionTranslator(AbstractDao.DB_TYPE_DB2).translate(e.getMessage(), e);
		}
	}
	/**
	 * 
	 * desc:根据条件查询对象列表（分页）
	 * <p>创建人：liuguangjun , May 10, 2013 4:37:00 PM</p>
	 * @param t
	 * @param startIndex 开始记录索引
	 * @param pageSize 一页的记录数
	 * @return
	 * @throws DataAccessException
	 */
	public List<T> findPageList(T t,Integer startIndex,Integer pageSize) throws DataAccessException {
		try {
			return getSqlMapClient().queryForList(entityClass.getSimpleName()+ POSTFIX_FIND,t,startIndex,pageSize);
		} catch (SQLException e) {
			throw new SQLErrorCodeSQLExceptionTranslator(AbstractDao.DB_TYPE_DB2).translate(e.getMessage(), e);
		}
	}
	/**
	 * 
	 * desc:根据map参数条件查询列表（分页）
	 * <p>创建人：liuguangjun , May 10, 2013 4:37:00 PM</p>
	 * @param t
	 * @param startIndex 开始记录索引
	 * @param pageSize 一页的记录数
	 * @return
	 * @throws DataAccessException
	 */
	public List<T> findPageList(Map<String,Object> queryMap,Integer startIndex,Integer pageSize) throws DataAccessException {
		try {
			return getSqlMapClient().queryForList(entityClass.getSimpleName()+ POSTFIX_FIND,queryMap,startIndex,pageSize);
		} catch (SQLException e) {
			throw new SQLErrorCodeSQLExceptionTranslator(AbstractDao.DB_TYPE_DB2).translate(e.getMessage(), e);
		}
	}
	/**
	 * 
	 * desc:根据条件查询对象列表（分页）
	 * <p>创建人：liuguangjun , May 10, 2013 4:37:00 PM</p>
	 * @param t
	 * @param startIndex 开始记录索引
	 * @param pageSize 一页的记录数
	 * @return
	 * @throws DataAccessException
	 */
	public Integer findPageList_count(Map<String,Object> queryMap) throws DataAccessException {
		try {
			return (Integer)getSqlMapClient().queryForObject(entityClass.getSimpleName()+POSTFIX_FIND+"_count",queryMap);
		} catch (SQLException e) {
			throw new SQLErrorCodeSQLExceptionTranslator(AbstractDao.DB_TYPE_DB2).translate(e.getMessage(), e);
		}
	}
	/**
	 * 
	 * desc:根据条件查询对象列表（分页）
	 * <p>创建人：liuguangjun , May 10, 2013 4:37:00 PM</p>
	 * @param t
	 * @param startIndex 开始记录索引
	 * @param pageSize 一页的记录数
	 * @return
	 * @throws DataAccessException
	 */
	public List<T> findPageList_count(T t,Integer startIndex,Integer pageSize) throws DataAccessException {
		try {
			return getSqlMapClient().queryForList(entityClass.getSimpleName()+"_count",t,startIndex,pageSize);
		} catch (SQLException e) {
			throw new SQLErrorCodeSQLExceptionTranslator(AbstractDao.DB_TYPE_DB2).translate(e.getMessage(), e);
		}
	}
	/*
	 * 根据条件查询对象（有分页）
	 * 
	 */
	public void pagedFindBy(PageBean pageBean, T t) throws DataAccessException {
		try {
			Integer pageSize=pageBean.getLength();
	    	Integer start=(pageBean.getCurrentPage()-1)*pageSize;
	    	Number totleRecord=(Number) getSqlMapClient().queryForObject(entityClass.getSimpleName()+"_count",t);//总条数
	    	List list=getSqlMapClientTemplate().getSqlMapClient().queryForList(entityClass.getSimpleName(),t,start,pageSize);
	    	pageBean.setTotalRecords(totleRecord.intValue());
	    	pageBean.setResults(list);
		} catch (SQLException e) {
			throw new SQLErrorCodeSQLExceptionTranslator(AbstractDao.DB_TYPE_DB2).translate(e.getMessage(), e);
		}
	}

	/*
	 * 保存对象
	 * 
	 */
	public void insert(T t) throws DataAccessException, IntegrityViolationException {
		try {
			getSqlMapClientTemplate().getSqlMapClient().insert(entityClass.getSimpleName() + POSTFIX_INSERT, t);
		} catch (SQLException e) {
			throw new SQLErrorCodeSQLExceptionTranslator(AbstractDao.DB_TYPE_DB2).translate(e.getMessage(), e);
		}
	}

	/*
	 * 更新对象
	 * 
	 */
	public int update(T t) throws DataAccessException {
		try {
			return getSqlMapClientTemplate().getSqlMapClient().update(entityClass.getSimpleName() + POSTFIX_UPDATE, t);
		} catch (SQLException e) {
			throw new SQLErrorCodeSQLExceptionTranslator(AbstractDao.DB_TYPE_DB2).translate(e.getMessage(), e);
		}
	}
	/**
	 * 
	 * desc:批量insert
	 * <p>创建人：liuguangjun , May 18, 2013 9:10:54 PM</p>
	 * @param clazz
	 * @param index
	 * @return
	 */
	public void batchInsert(final List<T> objList)throws DataAccessException {
		if (null == objList || objList.size() == 0) {
			return;
		}
		SqlMapClientCallback callback = new SqlMapClientCallback() {
			public Object doInSqlMapClient(SqlMapExecutor sqlMapExecutor)
					throws SQLException {
				int counter = 0;
				sqlMapExecutor.startBatch();
				for (T obj : objList) {
					sqlMapExecutor.insert(entityClass.getSimpleName()+POSTFIX_INSERT, obj);//insert
					counter++;
					if (counter % 1000 == 0) {
						// 设置一个计数器每隔1000条提交一次
						sqlMapExecutor.executeBatch();
						sqlMapExecutor.startBatch();
					}
				}
				sqlMapExecutor.executeBatch();
				return null;
			}
		};
		this.getSqlMapClientTemplate().execute(callback);
	}
	/**
	 * 
	 * desc:批量insert或update
	 * <p>创建人：liuguangjun , May 18, 2013 9:10:54 PM</p>
	 * @param clazz
	 * @param index
	 * @return
	 */
	public void batchInsertOrUpdate(final List<T> objList)throws DataAccessException {
		if (null == objList || objList.size() == 0) {
			return;
		}
		SqlMapClientCallback callback = new SqlMapClientCallback() {
			public Object doInSqlMapClient(SqlMapExecutor sqlMapExecutor)
					throws SQLException {
				int counter = 0;
				sqlMapExecutor.startBatch();
				for (T obj : objList) {
					T resObj=(T)sqlMapExecutor.queryForObject(entityClass.getSimpleName()+POSTFIX_FIND,obj);//get
					if(resObj==null){
						sqlMapExecutor.insert(entityClass.getSimpleName()+POSTFIX_INSERT, obj);//insert
					}else{
						sqlMapExecutor.insert(entityClass.getSimpleName()+POSTFIX_UPDATE, obj);//update
					}
					counter++;
					if (counter % 1000 == 0) {
						// 设置一个计数器每隔1000条提交一次
						sqlMapExecutor.executeBatch();
						sqlMapExecutor.startBatch();
					}
				}
				sqlMapExecutor.executeBatch();
				return null;
			}
		};
		this.getSqlMapClientTemplate().execute(callback);
	}
	
	
	/*
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型.
	 * 
	 * @param clazz clazz The class to introspect @param index the Index of the
	 * generic ddeclaration,start from 0. @return the index generic declaration,
	 * or <code>Object.class</code> if cannot be determined
	 */
	private static Class getSuperClassGenricType(Class clazz, int index) {
		Type genType = clazz.getGenericSuperclass();
		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		if (index >= params.length || index < 0) {
			return Object.class;
		}
		if (!(params[index] instanceof Class)) {
			return Object.class;
		}
		return (Class) params[index];
	}
}
